
/*
       	mm.h
        
        Macros, structs and methods used for memory management
        
        Meng Sun(c) leon.meng.sun@gmail.com
        Source code released under LGPLv3
        https://www.gnu.org/licenses/lgpl-3.0.txt
*/

#ifndef ISAMIPS_QEMU_MEMMGMT
#define ISAMIPS_QEMU_MEMMGMT

#include "mips32r2.h"

#define KSEG0BASEADDR 0x80000000
#define SYSTEMPAGESIZE 0x2000

struct _TLBItem{
	reg32b entryHi;
	reg32b entryLo0;
	reg32b entryLo1;
	reg32b pageMask;
};

typedef struct _TLBItem TLBItem;

#define WriteTLBItemByGivenIndex(index, tlbItem) asm volatile ( \
	"mtc0 %0, $0, 0\n\t" /*cp0 index*/ \
	"mtc0 %1, $10, 0\n\t" /*cp0 entryHi*/ \
	"mtc0 %2, $2, 0\n\t" /*cp0 entryLo0*/ \
	"mtc0 %3, $3, 0\n\t" /*cp0 entryLo1*/ \
	"mtc0 %4, $5, 0\n\t" /*cp0 pageMask*/ \
	"ehb\n\t" \
	"tlbwi\n\t" \
	"ehb\n\t" \
	: /*no outputs*/ \
	: "r" (index), "r" ((tlbItem).entryHi), "r" ((tlbItem).entryLo0), "r" ((tlbItem).entryLo1), "r" ((tlbItem).pageMask) \
	: /*no clobbers*/ \
)

#define WriteTLBItemByFetchedIndex(tlbItem) asm volatile ( \
	"mtc0 %0, $10, 0\n\t" /*cp0 entryHi*/ \
	"mtc0 %1, $2, 0\n\t" /*cp0 entryLo0*/ \
	"mtc0 %2, $3, 0\n\t" /*cp0 entryLo1*/ \
	"mtc0 %3, $5, 0\n\t" /*cp0 pageMask*/ \
	"ehb\n\t" \
	"tlbwi\n\t" \
	"ehb\n\t" \
	: /*no outputs*/ \
	: "r" ((tlbItem).entryHi), "r" ((tlbItem).entryLo0), "r" ((tlbItem).entryLo1), "r" ((tlbItem).pageMask) \
	: /*no clobbers*/ \
)

#define WriteTLBItemByRandom(tlbItem) asm volatile ( \
	"mtc0 %0, $10, 0\n\t" /*cp0 entryHi*/ \
	"mtc0 %1, $2, 0\n\t" /*cp0 entryLo0*/ \
	"mtc0 %2, $3, 0\n\t" /*cp0 entryLo1*/ \
	"mtc0 %3, $5, 0\n\t" /*cp0 pageMask*/ \
	"ehb\n\t" \
	"tlbwr\n\t" \
	"ehb\n\t" \
	: /*no outputs*/ \
	: "r" ((tlbItem).entryHi), "r" ((tlbItem).entryLo0), "r" ((tlbItem).entryLo1), "r" ((tlbItem).pageMask) \
	: /*no clobbers*/ \
)

#define ProbeTLBItemByEntryHi(entryHi, index) asm volatile ( \
	"mtc0 %1, $10, 0\n\t" /*cp0 entryHi*/ \
	"ehb\n\t" \
	"tlbp\n\t" \
	"ehb\n\t" \
	"mfc0 %0, $0, 0\n\t" /*cp0 index*/ \
	"ehb\n\t" \
	: "=r" (index) \
	: "r" (entryHi) \
	: /*no clobbers*/ \
)

#define ReadTLBItemByGivenIndex(index, tlbItem) asm volatile ( \
	"mtc0 %4, $0, 0\n\t" /*cp0 index*/ \
	"ehb\n\t" \
	"tlbr\n\t" \
	"ehb\n\t" \
	"mfc0 %0, $10, 0\n\t" /*cp0 entryHi*/ \
	"mfc0 %1, $2, 0\n\t" /*cp0 entryLo0*/ \
	"mfc0 %2, $3, 0\n\t" /*cp0 entryLo1*/ \
	"mfc0 %3, $5, 0\n\t" /*cp0 pageMask*/ \
	"ehb\n\t" \
	: "=r" ((tlbItem).entryHi), "=r" ((tlbItem).entryLo0), "=r" ((tlbItem).entryLo1), "=r" ((tlbItem).pageMask) \
	: "r" (index) \
	: /*no clobbers*/ \
)

#define ReadTLBItemByFetchedIndex(tlbItem) asm volatile ( \
	"tlbr\n\t" \
	"ehb\n\t" \
	"mfc0 %0, $10, 0\n\t" /*cp0 entryHi*/ \
	"mfc0 %1, $2, 0\n\t" /*cp0 entryLo0*/ \
	"mfc0 %2, $3, 0\n\t" /*cp0 entryLo1*/ \
	"mfc0 %3, $5, 0\n\t" /*cp0 pageMask*/ \
	"ehb\n\t" \
	: "=r" ((tlbItem).entryHi), "=r" ((tlbItem).entryLo0), "=r" ((tlbItem).entryLo1), "=r" ((tlbItem).pageMask) \
	: /*no inputs*/ \
	: /*no clobbers*/ \
)

#define TurnOffKusegMemMap asm volatile ( \
	"mfc0 $t0, $12, 0\n\t" /*cp0 status*/ \
	"li $t1, 0x00000004\n\t" \
	"xor $t0, $t0, $t1\n\t" /*erl = 1*/ \
	"mtc0 $t0, $12, 0\n\t" \
	: /*no outputs*/ \
	: /*no inputs*/ \
	: "t0", "t1" \
)

#define TurnOnKusegMemMap asm volatile ( \
	"mfc0 $t0, $12, 0\n\t" /*cp0 status*/ \
	"li $t1, 0xfffffffb\n\t" \
	"and $t0, $t0, $t1\n\t" /*erl = 0*/ \
	"mtc0 $t0, $12, 0\n\t" \
	: /*no outputs*/ \
	: /*no inputs*/ \
	: "t0", "t1" \
)

enum _MemoryCacheType{
	MCTCACHEABLE = 3,
	MCTNOCACHE = 2
};

typedef enum _MemoryCacheType MemoryCacheType;

enum _MemoryGlobalType{
	MGTGLOBAL = 1,
	MGTLOCAL = 0
};

typedef enum _MemoryGlobalType MemoryGlobalType;

enum _MemoryWriteType{
	MWTREADWRITE = 1,
	MWTREADONLY = 0
};

typedef enum _MemoryWriteType MemoryWriteType;

enum _MemoryValidType{
	MVTVALID = 1,
	MVTNOTVALID = 0
};

typedef enum _MemoryValidType MemoryValidType;

typedef enum _DODFlags DODFlags;

struct _DynamicObjectDescriptor{
	byte* start; /*in VMA*/
	uint32 size; /*in bytes*/
	struct _DynamicObjectDescriptor* prev;
	struct _DynamicObjectDescriptor* next;
} ALIGN4B ;

typedef struct _DynamicObjectDescriptor DynamicObjectDescriptor;

struct _MemoryPageDescriptor{
	byte* pmaStart;
	byte* vmaStart;
	uint32 size; /*in 8k pages*/
	struct _MemoryPageDescriptor* prev;
	struct _MemoryPageDescriptor* next;
} ALIGN4B ;

typedef struct _MemoryPageDescriptor MemoryPageDescriptor;

void mmInit(void);

sint8 mmAppendMPDToList(MemoryPageDescriptor*, MemoryPageDescriptor**);

sint8 mmRemoveMPDFromList(MemoryPageDescriptor*, MemoryPageDescriptor**);

sint8 mmCopyData(byte*, byte*, uint32, bool);

uint8 mmGetNextTLBTableIndex(void);

sint8 mmGetTLBItemFromMemoryPageDescriptor(TLBItem*, MemoryPageDescriptor*, uint8, MemoryCacheType, MemoryGlobalType, MemoryWriteType, MemoryValidType);

void* mmSysMAlloc(uint32);

sint32 mmSysMFree(void*);

public void mmCleanMPDFreeList(void);

MemoryPageDescriptor** mmGetSystemFreeMPDListHeadPtr(void);

MemoryPageDescriptor** mmGetSystemUsedMPDListHeadPtr(void);

DynamicObjectDescriptor** mmGetSystemFreeDODListHeadPtr(void);

DynamicObjectDescriptor** mmGetSystemUsedDODListHeadPtr(void);

public sint8 mmAppendDODToList(DynamicObjectDescriptor*, DynamicObjectDescriptor**);

public sint8 mmRemoveDODFromList(DynamicObjectDescriptor*, DynamicObjectDescriptor**);

public void mmCleanDODFreeList(void);

#endif

